/*
 * User.h
 *
 *  Created on: Jun 10, 2011
 *      Author: Mario Hock
 */

#ifndef USER_H_
#define USER_H_

#include "ariba/ariba.h"
#include <boost/shared_ptr.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/foreach.hpp>
#include <boost/filesystem.hpp>
#include <set>
#include "interfaces/LinkEstablishedInterface.h"
#include "Access_attributes.h"

#define for_each BOOST_FOREACH

using namespace std;

using boost::shared_ptr;
using boost::property_tree::ptree;
using boost::filesystem::directory_iterator;
using boost::filesystem::directory_entry;
using boost::filesystem::path;

typedef map<string, AccessPtr> AccessMap;

class User
{
public:
    typedef enum
    {
        NOT_CONNECTED = 0,
        CONNECTED = 1,
        CONNECTION_PENDING = 2,
        DISCONNECT_PENDING = 3,
        AUTHENTICATION_PENDING = 4,
        SEND_ESTABLISHED = 5,
        RECEIVE_ESTABLISHED = 6,
        CONNECTION_ERROR = 7,
        ERROR_NOT_CONNECTED = 8  // means, there was an error before (maybe it's resolved now.)
    } CONNECTION_STATUS;

    static boost::shared_ptr<User> createUser(string name);
    static boost::shared_ptr<User> createUser(const ariba::NodeID &id);
    static boost::shared_ptr<User> createUser(ptree &pt);

    virtual ~User();

    string get_name();
    string get_masked_name();
    bool set_name(string name);
    ariba::NodeID get_id();
    bool check_privilege_push();
    bool check_privilege_custody();

    void list_shares(ptree &pt);
    void list_accessible_files(ptree &pt, string dir);
    bool file_has_privilege(boost::filesystem::path dir, Access_attributes::ACCESS_RIGHTS priv);
    void grant_file_permissions(string dir, Access_attributes::ACCESS_RIGHTS priv);
    CONNECTION_STATUS get_connection_status();
    bool is_connected();
    bool connection_pending();
    bool is_disconnected();
    void set_connected(CONNECTION_STATUS conn);
    bool is_temporal();

    void register_for_link_up_event(LinkEstablishedInterface* listener);


    shared_ptr<ptree> save();
    void info(ptree &pt);

    bool operator!(void);

/* constructors -- use factory */
protected:
    User();
    User(string name);
    User(const ariba::NodeID &id);
    User(ptree &pt);


private:
    void give_self_reference(boost::shared_ptr<User> ptr);
    void insert_access(AccessPtr a);
    void insert_access(string path, Access_attributes::ACCESS_RIGHTS privileges);
    void update_access(string path, Access_attributes::ACCESS_RIGHTS privileges);
    void create_std_dirs();

    void list_dir(string dir, ptree &pt);
    void list_file(string path, ptree &pt);


private:
    string name;
    ariba::NodeID id;
    boost::weak_ptr<User> self_reference;

    bool allow_push;
    AccessMap access; // TODO, wär doch cool wenn jeder user einen anderen dateinamen zu gesicht bekommen könnte...
//    set<string> access;

    CONNECTION_STATUS connected;

    bool temporal;

    std::list<LinkEstablishedInterface*> link_up_listeners;

//    Flow_control* flow_control;

public:
    // XXX testing
    ariba::LinkID link;

};

typedef boost::shared_ptr<User> UserPtr;

#endif /* USER_H_ */
